import puppeteer, { Page } from "puppeteer-core"
import path from "path"
import fs from "fs-extra"
import { biliTrace, biliSuccess } from "@/services"

import {
  getLastPage,
  transform2WinPath,
  fullScreenChrome,
  desktopPath,
} from "@/utils"

/**
 *
 * @param resource bili目录
 *
 * @example
 * resource = /Users/kenny/Desktop/t_03/精神障碍护理学/bili
 */
const main = async (resource: string, cacheName: string) => {
  biliTrace.info("----------------------------------------")

  const folder = path.dirname(resource).replace(desktopPath, "")

  biliTrace.warn(1, folder, "进入流程")

  const jsonPath = path.join(resource, "b.json")

  const json = JSON.parse(fs.readFileSync(jsonPath, { encoding: "utf8" }))

  // const currentNetName = cacheName || (await getCurrentNetInterface())

  biliTrace.trace("2、切换到", cacheName, "缓存目录", "启动浏览器实例")

  const userDataDir = path.join(".cache", cacheName)

  const browser = await puppeteer.launch({
    headless: false,
    channel: "chrome",
    defaultViewport: null,
    userDataDir,

    args: [
      // "--disable-gpu",
      // "--disable-dev-shm-usage",
      // "--no-first-run",
      // "--no-zygote",
      // "--single-process",

      "--no-sandbox",
      "--disable-setuid-sandbox",
      "--disable-notifications",
      "--disable-extensions",
    ],
  })

  biliTrace.trace("3、打开：B站首页")

  const [page] = await browser.pages()

  await page.goto("https://www.bilibili.com/", { waitUntil: "load" })

  biliTrace.warn("4、执行：浏览器全屏脚本")
  fullScreenChrome()

  /**
   * 循5秒环检测登录状态
   */
  biliTrace.trace("5、循环检测登录状态")

  while (Date.now()) {
    const loginBtn = await page.$('.header-login-entry::-p-text("登录")')

    if (loginBtn) {
      biliTrace.info(cacheName, "未登录", "点击登录按钮，唤起登录框", "等待15s")
      await loginBtn.click()
      await page.waitForTimeout(15000)
    } else {
      biliTrace.warn(cacheName, "已经登录", "结束登录状态循环监听")
      break
    }
  }

  biliTrace.trace("6、", cacheName, "点击：上传按钮,等待页面跳转")

  /**
   * 点击并且监听浏览器跳转事件
   */
  await new Promise(resolve => {
    page.once("popup", async newPage => {
      await newPage?.waitForSelector("body")
      resolve(null)
    })

    page
      .locator(".right-entry-item--upload")
      .setTimeout(0)
      .click({ delay: 2000 })
  })

  biliTrace.trace("7、", "关闭：关闭首页")
  await page.close()

  biliTrace.trace("8、", "拿到新页面实例")
  const uploadPage = await getLastPage(browser)

  /**禁止打开新页面 防止异常出现*/
  browser.on("targetcreated", target => {
    target.page().then(n => n?.close())
  })

  biliTrace.info("9、", "进入上传流程")

  const step = async (p: Page) => {
    const uploadVideo = async () => {
      biliTrace.info("~~", "开始上传视频")

      const [videoFileChooser] = await Promise.all([
        p.waitForFileChooser(),

        p.locator(".bcc-upload-wrapper").click(),
      ])

      const mp4Path = path.join(transform2WinPath(json.mp4Path))

      await videoFileChooser.accept([mp4Path])
    }

    p.evaluate(() => {})

    /**
     * @warning
     * 此处应该是异步，方便后续的60s等待
     */
    uploadVideo()

    biliTrace.trace("~~", "等待60s", "为了确保封面图上传图片出现")

    await Promise.any([
      p.locator(".file-block-status-text .success::-p-text(上传完成)").wait(),

      p.locator(".icon-sprite-pause").click(),
    ])

    biliTrace.info("10、", "开始上传封面图", "将底层input展示出来后等2s再点击")

    const coverUploadBtn = await p.evaluateHandle(() => {
      const input = $(".cover-upload .bcc-upload-wrapper input")

      input.css({
        display: "block",
        padding: "50px",
        position: "absolute",
        top: 0,
        left: 0,
        zIndex: 999,
        background: "red",
      })

      return input.get(0) as HTMLElement
    })

    /**
     * 滚动到上传图片标签可视区域
     */
    await coverUploadBtn?.scrollIntoView()

    await p.waitForTimeout(2000)

    const [coverImageFileChooser] = await Promise.all([
      p.waitForFileChooser(),

      coverUploadBtn?.click(),
    ])

    const coverPngPath = transform2WinPath(json.coverPngPath)

    await coverImageFileChooser?.accept([coverPngPath])

    await p.locator(".bcc-button span::-p-text( 完成 )").click()

    biliTrace.trace("~~", "完成上传封面图")

    biliTrace.trace(
      "~~",
      "判断视频是否已上传完毕",
      "若已没有传完则：继续上传视频",
    )

    await p.evaluateHandle(() => {
      if (!$(".success:contains(上传完成)").length) {
        $(".file-block-icon-bg:has(.icon-sprite-play)").click()
      }
    })

    biliTrace.trace(
      "11、",
      "等待3s",
      "连续点击3次标题输入框，框选默认已输入的标题内容",
    )

    // await new Promise(r => setTimeout(r, 3000))
    await p.waitForTimeout(3000)

    const inputTitle = await p.waitForSelector(".input-instance .input-val")

    biliTrace.trace("~~", "等标题输入框出现后，将其滚动到可视区域再连续点击3次")

    await inputTitle?.scrollIntoView()

    await inputTitle?.click({ count: 3 })

    // await p.click(".input-instance .input-val", { count: 3 })

    biliTrace.trace("12、", "等待100ms", "输入：标题")

    await p.type(".input-instance .input-val", json.name, { delay: 100 })

    const isNeedSelectArea = await p.evaluate(() => {
      return !$(".select-item-cont-inserted:contains( 知识 → 校园学习)").length
    })

    biliTrace.info("~~", "是否需要选择：知识-校园学习", isNeedSelectArea)

    if (isNeedSelectArea) {
      biliTrace.info("14、", "等待3s", "点击：分区选择框右边的下拉图标按钮")
      await p.waitForTimeout(3000)

      const pulldownBtn = await p.evaluateHandle(() => {
        const pulldownBtn = <Element>(
          $(".video-type .icon-sprite-pulldown").get(0)
        )

        const rect = pulldownBtn.getBoundingClientRect()

        document.documentElement.scrollTop = rect.top / 2

        return pulldownBtn
      })

      await pulldownBtn.scrollIntoView()

      await pulldownBtn.click()

      biliTrace.trace("~~", "等待3s", "选择：知识")

      await p.waitForTimeout(3000)

      // await new Promise(r => setTimeout(r, 999999))
      await p.evaluate(() => {
        $(".drop-f-item:contains(知识)").click()
      })

      biliTrace.trace("~~", "等待3s", "选择：校园学习")

      await p.waitForTimeout(3000)

      await p.evaluate(() => {
        $(".item-main:contains(校园学习)").click()
      })
    }

    await p.waitForTimeout(3000)
    biliTrace.trace("~~", "等待标签输入框出现")

    await p.evaluate(() => {
      const input = <HTMLElement>(
        $('input[placeholder="按回车键Enter创建标签"]').get(0)
      )

      const rect = input.getBoundingClientRect()
      document.documentElement.scrollTop = rect.top / 2
    })

    biliTrace.trace("15、", "循环输入标签", "每隔3s输入一个")
    for (const tag of json.tags) {
      await p.type('input[placeholder="按回车键Enter创建标签"]', tag, {
        delay: 200,
      })

      await p.keyboard.press("Enter", { delay: 3000 })
    }

    await p.waitForTimeout(3000)

    biliTrace.info("17、", "输入：视频描述内容")
    await p.evaluate(function (text) {
      const editor = <HTMLInputElement>$(".ql-editor p").get(0)

      const editorRect = editor.getBoundingClientRect()

      document.documentElement.scrollTop = editorRect.top / 2

      editor.innerHTML = text
    }, json.desc)

    biliTrace.info("18、", "等待：上传完成", "暂时不考虑上传失败等特殊情况")

    /**
     * 最多等待15分钟
     */
    await p
      .locator(".success::-p-text(上传完成)")
      .setTimeout(15 * 60 * 1000)
      .wait()

    biliTrace.trace("19、", "上传完成", "点击：立即投稿按钮")

    await Promise.any([
      p.locator(".submit-add::-p-text(立即投稿)").click(),

      p.evaluate(() => {
        $(".submit-add").click()
      }),
    ])

    biliTrace.info("20、", "等待投稿结果")
    await Promise.any([
      p.locator("::-p-text(恭喜你上传第一个稿件，成为UP主~)").wait(),

      p.locator(".step-des::-p-text(稿件投递成功)").wait(),
    ])

    biliTrace.info("21、", "投稿成功，关闭浏览器实例")
    await browser.close()

    biliTrace.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", "\r\n\r\n")
    biliSuccess.fatal(resource, cacheName)
  }

  await step(uploadPage as Page)
}

export default main
